/*-------------------------------------------------------------------------
 * drawElements Image Library
 * --------------------------
 *
 * Copyright 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *//*!
 * \file
 * \brief Targa file operations.
 *//*--------------------------------------------------------------------*/

#include "deImage.h"
#include "deMemory.h"
#include "deInt32.h"

#include <stdio.h>

deImage* deImage_loadTarga (const char* fileName)
{
	deImage*	image = DE_NULL;
	FILE*		file;

	file = fopen(fileName, "rb");

	if (file != DE_NULL)
	{
		int				bytesRead;
		int				width;
		int				height;
		int				bufSize;
		int				stride;
		int				bitsPerPixel;
		deUint8*		buffer;
		deImageFormat	format;
		deBool			yFlipped;

		deUint8 tgaHeader[18];

		bytesRead = (int)fread(&tgaHeader, 1, 18, file);
		DE_TEST_ASSERT(bytesRead == 18);
		DE_TEST_ASSERT(tgaHeader[2] == 2);								/* truecolor, no encoding */
		DE_TEST_ASSERT(tgaHeader[17] == 0x00 || tgaHeader[17] == 0x20);	/* both y-directions supported, non-interlaced */

		yFlipped = (tgaHeader[17] & 0x20) == 0;

		/* Decode header. */
		width			= (int)(tgaHeader[12]) | ((int)(tgaHeader[13]) << 8);
		height			= (int)(tgaHeader[14]) | ((int)(tgaHeader[15]) << 8);
		bitsPerPixel	= tgaHeader[16];
		stride			= width * bitsPerPixel / 8;

		/* Allocate buffer. */
		bufSize	= stride;
		buffer	= deMalloc(bufSize);
		DE_TEST_ASSERT(buffer);

		/* Figure out format. */
		DE_TEST_ASSERT(bitsPerPixel == 24 || bitsPerPixel == 32);
		format = (bitsPerPixel == 32) ? DE_IMAGEFORMAT_ARGB8888 : DE_IMAGEFORMAT_XRGB8888;

		/* Create image. */
		image = deImage_create(width, height, format);
		DE_TEST_ASSERT(image);

		/* Copy pixel data. */
		{
			int	bpp = 4;
			int	x, y;

			for (y = 0; y < height; y++)
			{
				const deUint8*	src		= buffer;
				int				dstY	= yFlipped ? (height-1 - y) : y;
				deARGB*			dst		= (deUint32*)((deUint8*)image->pixels + dstY*image->width*bpp);
				fread(buffer, 1, bufSize, file);

				if (bitsPerPixel == 24)
				{
					for (x = 0; x < width; x++)
					{
						deUint8 b = *src++;
						deUint8 g = *src++;
						deUint8 r = *src++;
						*dst++ = deARGB_set(r, g, b, 0xFF);
					}
				}
				else
				{
					/* \todo [petri] Component order? */
					deUint8 a = *src++;
					deUint8 b = *src++;
					deUint8 g = *src++;
					deUint8 r = *src++;
					DE_ASSERT(bitsPerPixel == 32);
					*dst++ = deARGB_set(r, g, b, a);
				}
			}
		}

		deFree(buffer);
		fclose(file);
	}

	return image;
}

deBool deImage_saveTarga (const deImage* image, const char* fileName)
{
	deImage*	imageCopy	= DE_NULL;
	int			width		= image->width;
	int			height		= image->height;
	char		tgaHeader[18];
	FILE*		file;

	/* \todo [petri] Handle non-alpha images. */
	if (image->format != DE_IMAGEFORMAT_ARGB8888)
	{
		imageCopy = deImage_convertFormat(image, DE_IMAGEFORMAT_ARGB8888);
		if (!imageCopy)
			return DE_FALSE;

		image = imageCopy;
	}

	file = fopen(fileName, "wb");
	if (!file)
		return DE_FALSE;

	/* Set unused fields of header to 0 */
	memset(tgaHeader, 0, sizeof(tgaHeader));

	tgaHeader[1] = 0;	/* no palette */
	tgaHeader[2] = 2;	/* uncompressed RGB */

	tgaHeader[12] = (char)(width & 0xFF);
	tgaHeader[13] = (char)(width >> 8);
	tgaHeader[14] = (char)(height & 0xFF);
	tgaHeader[15] = (char)(height >> 8);
	tgaHeader[16] = 24;		/* bytes per pixel */
	tgaHeader[17] = 0x20;	/* Top-down, non-interlaced */

	fwrite(tgaHeader, 1, 18, file);

	/* Store pixels. */
	{
		const deUint32*	pixels	= image->pixels;
		int				ndx;

		for (ndx = 0; ndx < width * height; ndx++)
		{
			deUint32 c = pixels[ndx];
			fputc((deUint8)(c>>0), file);
			fputc((deUint8)(c>>8), file);
			fputc((deUint8)(c>>16), file);
		}
	}

	/* Cleanup and return. */
	fclose(file);
	if (imageCopy)
		deImage_destroy(imageCopy);

	return DE_TRUE;
}
